using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Gameplay.PVE.Effect;
using ImageEffects;
using NpcFramework;
using RootMotion.FinalIK;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using UnityEngine.Playables;
using Yoozoo.Mars.Got;

namespace com.yoozoo.gta.Gameplay.PVE.Editor
{
    
    public class ComponentUtil
    {
        public static T CopyComponent<T>(T original, GameObject destination) where T : Component
        {
            System.Type type = original.GetType();

            var dst = destination.GetComponent(type) as T;
            if (!dst) dst = destination.AddComponent(type) as T;

            var fields = GetAllFields(type);
            foreach (var field in fields)
            {
                if (field.IsStatic) continue;
                field.SetValue(dst, field.GetValue(original));
            }

            var props = type.GetProperties();
            foreach (var prop in props)
            {
                if (!prop.CanWrite || !prop.CanWrite || prop.Name == "name") continue;
                prop.SetValue(dst, prop.GetValue(original, null), null);
            }

            return dst as T;
        }

        public static IEnumerable<FieldInfo> GetAllFields(System.Type t)
        {
            if (t == null)
            {
                return Enumerable.Empty<FieldInfo>();
            }

            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
                                 BindingFlags.Static | BindingFlags.Instance |
                                 BindingFlags.DeclaredOnly;
            return t.GetFields(flags).Concat(GetAllFields(t.BaseType));
        }

    }

    public class ModelHitPointEditor
    {
        public static Transform FindChild(Transform trans, string goName)
        {
            Transform child = trans.Find(goName);
            if (child != null)
                return child;
 
            Transform go = null;
            for (int i = 0; i < trans.childCount; i++)
            {
                child = trans.GetChild(i);
                go = FindChild(child, goName);
                if (go != null)
                    return go;
            }
            return null;
        }

        private static List<string> buffPoints = new List<string>
        {
            "Bip001 Head",
            "Bip001 Spine",
            "Bip001 R Hand",
            "Bip001 L Hand",
        };

        private static List<string> hitPoints = new List<string>
        {
            "Bip001 Head",
            "Bip001 Spine",
            "Bip001 L Clavicle",
            "Bip001 R Clavicle",
            "Bip001 L Forearm",
            "Bip001 R Forearm"
        };

        private static List<string> WeaponPoints = new List<string>
        {
            "Bip001 Prop1",
            "Bip001 Prop2",
            "Weapon01",
        };
        
        [MenuItem("GTATools/GamePlay/PVE/ModelHitPoint/HitDuration", false, 66778899)]
        public static void CalculateHitDuration()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var modelHitPoint = obj.GetComponent<ModelHitPoint>();
                if (modelHitPoint != null)
                {
                    var animator = gameObjects[i].GetComponentInChildren<Animator>();
                    if (animator)
                    {
                        var animatorController = animator.runtimeAnimatorController as AnimatorOverrideController;
                        var clips = animatorController.animationClips;
                        for (int j = 0; j < clips.Length; j++)
                        {
                            var clip = clips[j];
                            if (clip.name.ToLower().Contains("hit"))
                            {
                                var duration = clip.length;
                                modelHitPoint.hitDuration = duration;
                                break;
                            }
                        }
                    }
                    PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                }
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        [MenuItem("GTATools/GamePlay/PVE/ModelHitPoint/Hit", false, 66778899)]
        public static void Hit()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var modelHitPoint = obj.GetComponent<ModelHitPoint>();
                if (modelHitPoint != null)
                {
                    modelHitPoint.hitPoints.Clear();
                    for (int j = 0; j < hitPoints.Count; j++)
                    {
                        Transform part = FindChild(obj.transform, hitPoints[j]);
                        if (part == null)
                        {
                            Debug.LogError(obj.name + "没有找到" + hitPoints[j]);
                        }
                        else
                        {
                            modelHitPoint.hitPoints.Add(part);
                        }
                    }
                    PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                }
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        
        [MenuItem("GTATools/GamePlay/PVE/ModelHitPoint/Buff", false, 66778899)]
        public static void Buff()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var modelHitPoint = obj.GetComponent<ModelHitPoint>();
                if (modelHitPoint != null)
                {
                    for (int j = 0; j < buffPoints.Count; j++)
                    {
                        Transform part = null;
                        if (j == 0)
                        {
                            var buff = FindChild(obj.transform, "[BuffPoint]");
                            if (buff == null)
                            {
                                buff = new GameObject("[BuffPoint]").transform;
                            }

                            var head = FindChild(obj.transform, "Bip001 Head");
                            if (head != null)
                            {
                                buff.transform.SetParent(head);
                                buff.transform.localPosition = Vector3.zero;
                                buff.transform.position += new Vector3(0,0.3f,0);
                            }
                            else
                            {
                                Debug.LogError(obj.name + "没有找到head点");
                                buff.transform.SetParent(obj.transform);
                                buff.transform.localPosition = Vector3.zero;
                                buff.transform.position += new Vector3(0,2.2f,0);
                            }
                            part = buff;
                        }
                        else
                        {
                            part = FindChild(obj.transform, buffPoints[j]);
                            if (part == null)
                            {
                                Debug.LogError(obj.name + "没有找到" + buffPoints[j]);
                                part = obj.transform;
                            }
                        }
                        if (modelHitPoint.buffEffectPoints.Count > j)
                        {
                            modelHitPoint.buffEffectPoints[j] = part;
                        }
                        else
                        {
                            modelHitPoint.buffEffectPoints.Add(part);
                        }
                    }
                    PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                }
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        [MenuItem("GTATools/GamePlay/PVE/ModelHitPoint/Hud", false, 66778899)]
        public static void Hud()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var modelHitPoint = obj.GetComponent<ModelHitPoint>();
                if (modelHitPoint != null)
                {
                    var hud = FindChild(obj.transform, "[HudPoint]");
                    if (hud == null)
                    {
                        hud = new GameObject("[HudPoint]").transform;
                    }

                    var head = FindChild(obj.transform, "Bip001 Head");
                    if (head != null)
                    {
                        hud.transform.SetParent(head);
                        hud.transform.localPosition = Vector3.zero;
                        hud.transform.position += new Vector3(0,0,0);
                    }
                    else
                    {
                        Debug.LogError(obj.name + "没有找到head点");
                        hud.transform.SetParent(obj.transform);
                        hud.transform.localPosition = Vector3.zero;
                        hud.transform.position += new Vector3(0,2.2f,0);
                    }

                    modelHitPoint.hudPoint = hud;

                    PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                }
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        [MenuItem("GTATools/GamePlay/PVE/ModelHitPoint/AimIK", false, 66778899)]
        public static void AimIK()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);

                var aimIk = obj.GetComponent<AimIK>();
                if (aimIk == null)
                {
                    aimIk = obj.AddComponent<AimIK>();
                    aimIk.fixTransforms = true;
                    var prop = FindChild(obj.transform, "Bip001 Prop1");
                    if (prop == null)
                    {
                        Debug.LogError(gameObjects[i].name+" 没有Bip001 Prop1");
                    }
                    else
                    {
                        aimIk.solver.transform = prop;
                        aimIk.solver.axis = new Vector3(0,0,1);
                        aimIk.solver.poleAxis = new Vector3(0,1,0);
                        aimIk.solver.clampWeight = 0.1f;
                        aimIk.solver.clampSmoothing = 2;
                        aimIk.solver.poleWeight = 0;
                        aimIk.solver.tolerance = 0;
                        aimIk.solver.maxIterations = 4;
                        aimIk.solver.SetIKPositionWeight(0);
                        aimIk.solver.useRotationLimits = true;

                        var spine = FindChild(obj.transform, "Bip001 Spine2");
                        if (spine == null)
                        {
                            Debug.LogError(gameObjects[i].name+" Bip001 Spine2");
                            spine = FindChild(obj.transform, "Bip001 Spine1");
                            if (spine == null)
                            {
                                Debug.LogError(gameObjects[i].name+" Bip001 Spine1");
                                spine = FindChild(obj.transform, "Bip001 Spine");
                            }
                        }

                        if (spine != null)
                        {
                            aimIk.solver.AddBone(spine);
                        }
                        PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                    }
                    GameObject.DestroyImmediate(obj); 
                }

            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        [MenuItem("GTATools/GamePlay/PVE/ParticleGrade", false, 66778899)]
        public static void ParticleGrade()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var controller = obj.GetOrAddComponent<PveEffectController>();
                controller.InitGrading();
                PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        [MenuItem("GTATools/GamePlay/PVE/EffectController", false, 66778899)]
        public static void AddPveEffectController()
        {
            var gameObjects = Selection.gameObjects;
            
            StringBuilder sb = new StringBuilder();
            sb.AppendLine();

            StringBuilder sb2 = new StringBuilder();
            sb2.AppendLine();
            
            StringBuilder sb3 = new StringBuilder();
            sb3.AppendLine();
            
            bool warning = false;
            
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var controller = obj.GetOrAddComponent<PveEffectController>();
                controller.GetData();

                if (controller.PlayTime > 2 && Math.Abs(controller.PlayTime - 5.123f) > 0.001f)
                {
                    warning = true;
                    sb.AppendLine(gameObjects[i].name + "  的时长大于2秒,为：" + controller.PlayTime);
                }
                
                if (controller.IsLoop)
                {
                    warning = true;
                    sb2.AppendLine(gameObjects[i].name + "  粒子带有循环或有Animator，需要主动设置销毁时间");
                }

                if (controller.particleSystems!=null && controller.particleSystems.Length > 8)
                {
                    warning = true;
                    sb3.AppendLine(gameObjects[i].name + "  粒子发射器数量过大为：" + controller.particleSystems.Length);
                }
                
                PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                GameObject.DestroyImmediate(obj); 
            }

            if (warning)
            {
                UnityEngine.Debug.LogError(sb.Append(sb2).Append(sb3));
            }
            
            
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        [MenuItem("GTATools/GamePlay/PVE/RemoveShadow", false, 66778899)]
         public static void RemoveShadow()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var skin = obj.GetComponentsInChildren<SkinnedMeshRenderer>();
                for (int j = 0; j < skin.Length; j++)
                {
                    var mats = skin[j].sharedMaterials;
                    bool hasShadow = false;
                    for (int k = 0; k < mats.Length; k++)
                    {
                        if (mats[k].shader.name.Contains("Shadow"))
                        {
                            mats[k] = null;
                            hasShadow = true;
                            break;
                        }
                    }

                    if (hasShadow)
                    {
                        var newMats = new Material[skin[j].sharedMaterials.Length - 1];
                        int index = 0;
                        for (int k = 0; k < mats.Length; k++)
                        {
                            if (mats[k] != null)
                            {
                                newMats[index] = skin[j].sharedMaterials[k];
                                index++;
                            }
                        }
                        skin[j].sharedMaterials = newMats;
                    }
                }
                var mesh = obj.GetComponentsInChildren<MeshRenderer>();
                for (int j = 0; j < mesh.Length; j++)
                {
                    var mats = mesh[j].sharedMaterials;
                    bool hasShadow = false;
                    for (int k = 0; k < mats.Length; k++)
                    {
                        if (mats[k].shader.name.Contains("Shadow"))
                        {
                            mats[k] = null;
                            hasShadow = true;
                            break;
                        }
                    }

                    if (hasShadow)
                    {
                        var newMats = new Material[mesh[j].sharedMaterials.Length - 1];
                        int index = 0;
                        for (int k = 0; k < mats.Length; k++)
                        {
                            if (mats[k] != null)
                            {
                                newMats[index] = mesh[j].sharedMaterials[k];
                                index++;
                            }
                        }
                        mesh[j].sharedMaterials = newMats;
                    }
                }
                PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        
        [MenuItem("GTATools/GamePlay/PVE/Shadow", false, 66778899)]
        public static void AddShadow()
        {
            var modelShadow =
                AssetDatabase.LoadAssetAtPath<Material>("Assets/ResourcesAssets/Pve/Materials/mat_model_shadow.mat");
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var skin = obj.GetComponentsInChildren<SkinnedMeshRenderer>();
                for (int j = 0; j < skin.Length; j++)
                {
                    var mats = skin[j].sharedMaterials;
                    bool hasShadow = false;
                    for (int k = 0; k < mats.Length; k++)
                    {
                        if (mats[k].shader.name.Contains("Shadow"))
                        {
                            hasShadow = true;
                            break;
                        }
                    }

                    if (!hasShadow)
                    {
                        var newMats = new Material[skin[j].sharedMaterials.Length + 1];
                        for (int k = 0; k < mats.Length; k++)
                        {
                            newMats[k] = skin[j].sharedMaterials[k];
                        }
                        newMats[newMats.Length - 1] = modelShadow;
                        skin[j].sharedMaterials = newMats;
                    }
                }
                var mesh = obj.GetComponentsInChildren<MeshRenderer>();
                for (int j = 0; j < mesh.Length; j++)
                {
                    var mats = mesh[j].sharedMaterials;
                    bool hasShadow = false;
                    for (int k = 0; k < mats.Length; k++)
                    {
                        if (mats[k].shader.name.Contains("Shadow"))
                        {
                            hasShadow = true;
                            break;
                        }
                    }

                    if (!hasShadow)
                    {
                        var newMats = new Material[mesh[j].sharedMaterials.Length + 1];
                        for (int k = 0; k < mats.Length; k++)
                        {
                            newMats[k] = mesh[j].sharedMaterials[k];
                        }
                        newMats[newMats.Length - 1] = modelShadow;
                        mesh[j].sharedMaterials = newMats;
                    }
                }
                PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                GameObject.DestroyImmediate(obj); 
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        [MenuItem("GTATools/GamePlay/PVE/ResetRq", false, 66778899)]
        public static void ResetRq()
        {
            var baseIndex = 3001;
            HashSet<Material> matDic = new HashSet<Material>();
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var renderer = gameObjects[i].GetComponentsInChildren<Renderer>();
                for (int j = 0; j < renderer.Length; j++)
                {
                    var mats = renderer[j].sharedMaterials;
                    for (int k = 0; k < mats.Length; k++)
                    {
                        var mat = mats[k];
                        if (mat == null)
                        {
                            continue;
                        }
                        if (!matDic.Contains(mat))
                        {
                            matDic.Add(mat);
                            mat.renderQueue = baseIndex;
                            baseIndex++;
                        }
                    }
                }
            }
            Debug.LogError(baseIndex);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        private static List<string> npcHand = new List<string>
        {
            "Bip001 R Hand"
        };
        
        [MenuItem("GTATools/GamePlay/RpgModel/模型导入器设置npc", false, 66778899)]
        public static void ImportModelNPC()
        {
            var objects = Selection.objects;
            for (int i = 0; i < objects.Length; i++)
            {
                var path = AssetDatabase.GetAssetPath(objects[i]);
                var oldGameObject = GameObject.Instantiate(objects[i]) as GameObject;
                //先找到fbx的资源
                GameObject fullObject = null;
                var animators = oldGameObject.GetComponentsInChildren<Animator>();
                Animator oldAnimator = null;
                ModelImporter importer = null;
                var modelPath = string.Empty;
                for (int o = 0; o < animators.Length; o++)
                {
                    var animator = animators[o];
                    var avatar = animator.avatar;
                    if (avatar != null)
                    {
                        var avatarPath = AssetDatabase.GetAssetPath(avatar);
                        modelPath = avatarPath;
                        importer = AssetImporter.GetAtPath(avatarPath) as ModelImporter;
                        importer.optimizeGameObjects = false;
                        AssetDatabase.WriteImportSettingsIfDirty(avatarPath);
                        AssetDatabase.SaveAssets();
                        AssetDatabase.Refresh();
                        fullObject = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(avatarPath));
                        oldAnimator = animator;
                        break;
                    }
                }
                
                if (importer && fullObject)
                {
                    List<string> pointPathList = new List<string>();
                    //找到需要导出的点,把他们export
                    //路径形式 = “Root/Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/Bip001 Spine2/Bip001 R Clavicle/Bip001 R UpperArm/Bip001 R Forearm/Bip001 R Hand/Bip001 Prop1”
                    var extraPoint = new List<string>();
                    extraPoint.AddRange(npcHand);
                    for (int j = 0; j < extraPoint.Count; j++)
                    {
                        var name = extraPoint[j];
                        Transform point = FindChild(fullObject.transform, name);
                        if (point == null)
                        {
                            UnityEngine.Debug.LogError(fullObject.name + "没有找到" + name);
                        }
                        else
                        {
                            //生成路径
                            string pointPath = string.Empty;
                            var current = point;
                            while (true)
                            {
                                pointPath = current.name + pointPath;
                                current = current.parent;
                                if (current != null && current != fullObject.transform)
                                {
                                    pointPath = "/" + pointPath;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            pointPathList.Add(pointPath);
                            UnityEngine.Debug.Log(pointPath);
                        }
                    }

                    importer.optimizeGameObjects = true;
                    string[] extraPoints = new string[pointPathList.Count];
                    for (int j = 0; j < pointPathList.Count; j++)
                    {
                        extraPoints[j] = pointPathList[j];
                    }
                    importer.extraExposedTransformPaths = extraPoints;
                    GameObject.DestroyImmediate(fullObject);
                    AssetDatabase.WriteImportSettingsIfDirty(modelPath);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }
                
                var newObj = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(modelPath));
                //animator赋值
                //注意，从fbx实例化出来的prefab会自带一个animator，所以不能添加
                var newAnimator = newObj.GetComponent<Animator>();
                newAnimator.runtimeAnimatorController = oldAnimator.runtimeAnimatorController;
                var skinnedMeshRenderers = oldGameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
                var newSKinnedMeshRenderes = newObj.GetComponentsInChildren<SkinnedMeshRenderer>();
                for (int o = 0; o < skinnedMeshRenderers.Length; o++)
                {
                    var skinnedMeshRenderer = skinnedMeshRenderers[o];
                    if (skinnedMeshRenderer)
                    {
                        //var meshPath = AssetDatabase.GetAssetPath(skinnedMeshRenderer.sharedMesh);
                        //var newObj = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(meshPath));
                        var oldRenderObjectName = skinnedMeshRenderer.gameObject.name;
                        var newRenderObject = FindChild(newObj.transform, oldRenderObjectName);
                        if (newRenderObject == null)
                        {
                            Debug.LogError(oldRenderObjectName);
                        }
                        else
                        {
                            var newSkinnedMeshRenderer = newRenderObject.GetComponent<SkinnedMeshRenderer>();
                            newSkinnedMeshRenderer.sharedMaterials = skinnedMeshRenderer.sharedMaterials;
                        }
                    }
                }
                
                newObj.SetLayerRecursively(oldGameObject.layer);
                var seekerSpeed = oldGameObject.GetComponent<SeekerSpeed>();
                if (seekerSpeed)
                {
                    UnityEditorInternal.ComponentUtility.CopyComponent(seekerSpeed);
                    UnityEditorInternal.ComponentUtility.PasteComponentAsNew(newObj);
                }
                
                var prefab = PrefabUtility.SaveAsPrefabAsset(newObj, path);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                    
                //lightElement
                var lightElement = prefab.GetOrAddComponent<LightElement>();
                lightElement.FindLightRenderer();
                    
                GameObject.DestroyImmediate(oldGameObject);
                GameObject.DestroyImmediate(newObj);

            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        private static List<string> GetTransformNames(List<Transform> transforms)
        {
            var list = new List<string>();
            for (int i = 0; i < transforms.Count; i++)
            {
                list.Add(transforms[i].name);
            }
            return list;
        }

        private static List<Transform> GetNewNodesFromOrigin(Transform transform, Transform origin)
        {
            var list = new List<Transform>();
            for (int i = 0; i < transform.childCount; i++)
            {
                var t = transform.GetChild(i);
                if (!FindChild(origin, t.name))
                {
                    list.Add(t);
                }
                else
                {
                    list.AddRange(GetNewNodesFromOrigin(t,origin));
                }
            }

            return list;
        }

        private static Transform GetBoneTemplate()
        {
            var path = "Assets/Arts/Character/Role/hero/Template/Rpg/Model/BoneTemplate.prefab";
            var gameObject = AssetDatabase.LoadAssetAtPath<GameObject>(path);
            return gameObject.transform;
        }

        private static List<string> GetDiffBonePathFromTemplate(Transform root)
        {
            var list = new List<string>();
            var template = GetBoneTemplate();
            var diff = GetNewNodesFromOrigin(root, template);
            for (int i = 0; i < diff.Count; i++)
            {
                list.Add(GetPathFromRoot(diff[i],root));
            }
            return list;
        }
        
        [MenuItem("GTATools/GamePlay/RpgModel/修改prefab的模型为optimized", false, 66778899)]
        public static void ImportModel()
        {
            var objects = Selection.objects;
            for (int i = 0; i < objects.Length; i++)
            {
                var gameObject = objects[i] as GameObject;
                var animator = gameObject.GetComponent<Animator>();
                var path = AssetDatabase.GetAssetPath(animator.avatar);
                ModelImporter importer = AssetImporter.GetAtPath(path) as ModelImporter;
                if (importer)
                {
                    if (importer.optimizeGameObjects)
                    {
                        continue;
                    }
                    var modelHitPoint = gameObject.GetComponent<ModelHitPoint>();
                    //先实例化一个出来，看节点的路径
                    var obj = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(path));
                    obj.transform.localPosition = Vector3.zero;
                    obj.transform.localEulerAngles = Vector3.zero;
                    List<string> pointPathList = new List<string>();
                    //找到需要导出的点的名字，从modelHitPoint中着手
                    var extraPoint = new List<string>();
                    extraPoint.AddRange(GetTransformNames(modelHitPoint.hitPoints));
                    extraPoint.AddRange(GetTransformNames(modelHitPoint.gunPoints));
                    extraPoint.AddRange(GetTransformNames(modelHitPoint.buffEffectPoints));
                    extraPoint.AddRange(GetTransformNames(modelHitPoint.skillEffectPoints));
                    
                    
                    //然后找到程序prefab比fbx多出来的东西
                    var newNodes = GetNewNodesFromOrigin(gameObject.transform, obj.transform);
                    for (int j = 0; j < newNodes.Count; j++)
                    {
                        var parent = newNodes[j].parent;
                        if (parent != gameObject.transform)
                        {
                            extraPoint.Add(parent.name);
                        }
                    }
                    
                    
                    for (int j = 0; j < extraPoint.Count; j++)
                    {
                        var name = extraPoint[j];
                        Transform point = FindChild(obj.transform, name);
                        if (point == null)
                        {
                            //UnityEngine.Debug.LogError(gameObject.name + "没有找到" + name);
                        }
                        else
                        {
                            //生成路径
                            string pointPath = string.Empty;
                            var current = point;
                            while (true)
                            {
                                pointPath = current.name + pointPath;
                                current = current.parent;
                                if (current != null && current != obj.transform)
                                {
                                    pointPath = "/" + pointPath;
                                }
                                else
                                {
                                    break;
                                }
                            }
                            pointPathList.Add(pointPath);
                            UnityEngine.Debug.Log(pointPath);
                        }
                    }

                    var diffPathFromTemplate =
                        GetDiffBonePathFromTemplate(gameObject.GetComponentInChildren<SkinnedMeshRenderer>().rootBone);
                    for (int j = 0; j < diffPathFromTemplate.Count; j++)
                    {
                        Debug.LogError("多出来的骨骼 " +  diffPathFromTemplate[j]);
                    }
                    pointPathList.AddRange(diffPathFromTemplate);
                    
                    importer.optimizeGameObjects = true;
                    string[] extraPoints = new string[pointPathList.Count];
                    for (int j = 0; j < pointPathList.Count; j++)
                    {
                        extraPoints[j] = pointPathList[j];
                    }
                    importer.extraExposedTransformPaths = extraPoints;
                    GameObject.DestroyImmediate(obj);
                    AssetDatabase.WriteImportSettingsIfDirty(path);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                    var newObject = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(path));
                    for (int j = 0; j < newNodes.Count; j++)
                    {
                        var newNode = GameObject.Instantiate(newNodes[j].gameObject);
                        newNode.name = newNodes[j].name;
                        newNode.transform.SetParent(FindChild(newObject.transform,newNodes[j].parent.name));
                        newNode.transform.localPosition = newNodes[j].transform.localPosition;
                        newNode.transform.localEulerAngles = newNodes[j].transform.localEulerAngles;
                        newNode.transform.localScale = newNodes[j].transform.localScale;
                    }
                    var skinnedMeshRenderers = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
                    for (int o = 0; o < skinnedMeshRenderers.Length; o++)
                    {
                        var skinnedMeshRenderer = skinnedMeshRenderers[o];
                        if (skinnedMeshRenderer)
                        {
                            //var meshPath = AssetDatabase.GetAssetPath(skinnedMeshRenderer.sharedMesh);
                            //var newObj = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(meshPath));
                            var oldRenderObjectName = skinnedMeshRenderer.gameObject.name;
                            var newRenderObject = FindChild(newObject.transform, oldRenderObjectName);
                            if (newRenderObject == null)
                            {
                                Debug.LogError(oldRenderObjectName);
                            }
                            else
                            {
                                var newSkinnedMeshRenderer = newRenderObject.GetComponent<SkinnedMeshRenderer>();
                                newSkinnedMeshRenderer.sharedMaterials = skinnedMeshRenderer.sharedMaterials;
                            }
                        }
                    }

                    //animator
                    var newAnimator = newObject.GetComponent<Animator>();
                    newAnimator.runtimeAnimatorController = animator.runtimeAnimatorController;
                    newObject.name = gameObject.name;
                    //modelHitPoint
                    var newModelHitPoint = newObject.GetOrAddComponent<ModelHitPoint>();
                    CopyModelHitPoint(modelHitPoint, newModelHitPoint);

                    var aimIk = gameObject.GetComponent<AimIK>();
                    if (aimIk)
                    {
                        var newAimIk = ComponentUtil.CopyComponent<AimIK>(aimIk,newObject);
                        newAimIk.solver.transform = aimIk.solver.transform;
                        newAimIk.solver.bones = new IKSolver.Bone[aimIk.solver.bones.Length];
                        for (int j = 0; j < aimIk.solver.bones.Length; j++)
                        {
                            newAimIk.solver.bones[j] = new IKSolver.Bone(FindChild(obj.transform, aimIk.solver.bones[j].transform.name));
                        }
                    }
                    
                    newObject.SetLayerRecursively(gameObject.layer);
                    
                    PrefabUtility.SaveAsPrefabAsset(newObject, AssetDatabase.GetAssetPath(gameObject));
                    //GameObject.DestroyImmediate(newObject);
                
                    var lightElement = gameObject.GetOrAddComponent<LightElement>();
                    lightElement.FindLightRenderer();
                    lightElement.controllerMark = "rpgScene";
                    GameObject.DestroyImmediate(newObject);
                }

            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        private static string GetAssetPathByDirectoryPath(string directoryPath)
        {
            var index = directoryPath.IndexOf("Assets");
            if (index >= 0)
            {
                var assetPath = directoryPath.Substring(index);
                assetPath = assetPath.Replace("\\","/");
                return assetPath;
            }
            return directoryPath;
        }
        
        [MenuItem("GTATools/GamePlay/RpgModel/根据fbx创建模型", false, 0)]
        public static void CreateModelPrefab()
        {
            var objects = Selection.objects;
            for (int i = 0; i < objects.Length; i++)
            {
                var path = AssetDatabase.GetAssetPath(objects[i]);
                if (!path.EndsWith(".fbx") && !path.EndsWith(".FBX"))
                {
                    continue;
                }
                var obj = GameObject.Instantiate(objects[i]) as GameObject;
                obj.name = objects[i].name;
                var modelDirectory = Directory.GetParent(path);
                if (modelDirectory != null)
                {
                    var rootDirectory = modelDirectory.Parent;
                    if (rootDirectory != null)
                    {
                        bool hasAnimator = false;
                        bool hasMaterial = false;
                        var dirs = rootDirectory.GetDirectories();
                        for (int j = 0; j < dirs.Length; j++)
                        {
                            //寻找材质
                            if (dirs[j].Name.ToLower().Contains("material"))
                            {
                                var files = dirs[j].GetFiles();
                                var skinnedMeshRenderers = obj.GetComponentsInChildren<SkinnedMeshRenderer>();
                                for (int k = 0; k < skinnedMeshRenderers.Length; k++)
                                {
                                    if (files.Length > k)
                                    {
                                        if (files[k].Name.ToLower().EndsWith(".mat"))
                                        {
                                            var assetPath = GetAssetPathByDirectoryPath(files[k].FullName);
                                            var mat = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
                                            skinnedMeshRenderers[k].sharedMaterial = mat;
                                            hasMaterial = true;
                                        }
                                    }
                                }
                            }
                            //寻找状态机
                            if (dirs[j].Name.ToLower().Contains("animator"))
                            {
                                var files = dirs[j].GetFiles();
                                for (int k = 0; k < files.Length; k++)
                                {
                                    var file = files[k];
                                    if (file.Name.ToLower().EndsWith(".controller"))
                                    {
                                        var assetPath = GetAssetPathByDirectoryPath(files[k].FullName);
                                        var animator = AssetDatabase.LoadAssetAtPath<AnimatorController>(assetPath);
                                        obj.GetComponent<Animator>().runtimeAnimatorController = animator;
                                        hasAnimator = true;
                                    }
                                }
                            }
                        }

                        if (!hasMaterial)
                        {
                            Debug.LogError(obj.name + "没有找到材质");
                        }

                        if (!hasAnimator)
                        {
                            Debug.LogError(obj.name + "没有找到状态机");
                            //帮他创建一个状态机
                            var templateAnimatorPath =
                                "Assets/Arts/Character/Role/hero/Template/Rpg/Animator/HeroTemplateNew.controller";
                            var templateAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(templateAnimatorPath);
                            var animatorControllerPath = rootDirectory.FullName + "\\Animator";
                            if (!Directory.Exists(animatorControllerPath))
                            {
                                Directory.CreateDirectory(animatorControllerPath);
                            }
                            var animatorController = new AnimatorOverrideController();
                            animatorController.runtimeAnimatorController = templateAnimatorController;
                            
                            //替换动作

                            var overrides =
                                new List<KeyValuePair<AnimationClip, AnimationClip>>(animatorController.overridesCount);
                            animatorController.GetOverrides(overrides);
                            var animationsPath = rootDirectory.FullName + "\\Animations";
                            if (!Directory.Exists(animationsPath))
                            {
                                Debug.LogError("没有找到动画文件");
                                continue;
                            }
                            var animationsFiles = Directory.GetFiles(animationsPath);
                            
                            for (int k = 0; k < overrides.Count; k++)
                            {
                                //overrides[k] = 
                                var originName = overrides[k].Key.name;
                                bool hasFound = false;
                                //遍历动作
                                for (int o = 0; o < animationsFiles.Length; o++)
                                {
                                    if (hasFound)
                                    {
                                        break;
                                    }
                                    if (animationsFiles[o].ToLower().EndsWith(".fbx"))
                                    {
                                        var animationPath = GetAssetPathByDirectoryPath(animationsFiles[o]);
                                        var clips = AssetDatabase.LoadAllAssetsAtPath(animationPath);
                                        for (int oo = 0; oo < clips.Length; oo++)
                                        {
                                            if (clips[oo] is AnimationClip clip && clip.name.EndsWith(originName))
                                            {
                                                overrides[k] = new KeyValuePair<AnimationClip, AnimationClip>(overrides[k].Key,clip);
                                                hasFound = true;
                                            }
                                        }
                                    }
                                }

                                if (!hasFound)
                                {
                                    Debug.LogError(originName+"没有对应的动作");
                                }
                            }
                            animatorController.ApplyOverrides(overrides);

                            var assetPath = GetAssetPathByDirectoryPath(animatorControllerPath) + "/" + obj.name +
                                            ".overrideController";
                          
                            AssetDatabase.CreateAsset(animatorController,assetPath);
                            AssetDatabase.SaveAssets();
                            AssetDatabase.Refresh();
                            obj.GetComponent<Animator>().runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(assetPath);
                        }
                    }

                    var modelHitPoint = obj.AddComponent<ModelHitPoint>();
                    modelHitPoint.hitPoints = new List<Transform>();
                    for (int j = 0; j < hitPoints.Count; j++)
                    {
                        Transform part = FindChild(obj.transform, hitPoints[j]);
                        if (part == null)
                        {
                            Debug.LogError(obj.name + "没有找到" + hitPoints[j]);
                        }
                        else
                        {
                            modelHitPoint.hitPoints.Add(part);
                        }
                    }

                    modelHitPoint.buffEffectPoints = new List<Transform>();
                    for (int j = 0; j < buffPoints.Count; j++)
                    {
                        Transform part = FindChild(obj.transform, buffPoints[i]);
                        if (part)
                        {
                            var point = new GameObject("[BuffPoint]" + (j + 1));
                            point.transform.SetParent(part);
                            if (j == 0)
                            {
                                point.transform.localPosition = new Vector3(0,2.2f,0);
                            }
                            else
                            {
                                point.transform.localPosition = Vector3.zero;
                            }

                            point.transform.localEulerAngles = Vector3.zero;
                            modelHitPoint.buffEffectPoints.Add(point.transform);
                        }
                    }
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                    var prefabPath = "Assets/ResourcesAssets/Pve/Prefabs/Hero/" + obj.name + ".prefab";
                    var prefab = PrefabUtility.SaveAsPrefabAsset(obj, prefabPath);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                    
                    //lightElement
                    var lightElement = prefab.GetOrAddComponent<LightElement>();
                    lightElement.FindLightRenderer();

                }
                GameObject.DestroyImmediate(obj);
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        

        private class PlaneInfo
        {
            public float z;
            public Plane plane;
            public Vector3 centerPosition;
        }
        
        private static void CreateWeaponPoints(GameObject prop,ref GameObject gunPoint,ref GameObject bulletCase,bool setParent = false)
        {
            var pointTrans = FindChild(prop.transform, "[GunPoint");
            var bulletCaseTrans = FindChild(prop.transform, "[BulletCase]");
            bool needOverrideGunPoint = false;
            bool needOverrideBulletCase = false;
            if (pointTrans)
            {
                gunPoint = pointTrans.gameObject;
            }
            else
            {
                needOverrideGunPoint = true;
                gunPoint = new GameObject("[GunPoint]");
            }

            if (bulletCaseTrans)
            {
                bulletCase = bulletCaseTrans.gameObject;
            }
            else
            {
                needOverrideBulletCase = true;
                bulletCase = new GameObject("[BulletCase]");
            }
            var newProp = GameObject.Instantiate(prop);
            newProp.transform.position = Vector3.zero;
            newProp.transform.forward = Vector3.forward;
            var newPropTrans = newProp.transform;
            //找到武器的最前方和最上方

            var frontest = Vector3.zero;
            var frontestNormal = Vector3.zero;
            var backest = Vector3.zero;

            var zList = new List<PlaneInfo>();
            var meshFilters = newProp.GetComponentsInChildren<MeshFilter>();
            var meshs = new List<Mesh>();
            for (int i = 0; i < meshFilters.Length; i++)
            {
                meshs.Add(meshFilters[i].sharedMesh);
            }

            var skinned = newProp.GetComponentsInChildren<SkinnedMeshRenderer>();
            for (int i = 0; i < skinned.Length; i++)
            {
                meshs.Add(skinned[i].sharedMesh);
            }
            for (int i = 0; i < meshs.Count; i++)
            {
                var mesh = meshs[i];
                for (int j = 0; j < mesh.triangles.Length; j += 3)
                {
                    var v1 = mesh.triangles[j];
                    var v2 = mesh.triangles[j + 1];
                    var v3 = mesh.triangles[j + 2];
                    var p1 = newPropTrans.TransformPoint(mesh.vertices[v1]);
                    var p2 = newPropTrans.TransformPoint(mesh.vertices[v2]);
                    var p3 = newPropTrans.TransformPoint(mesh.vertices[v3]);
                    var averageX = (p1.x + p2.x + p3.x) / 3;
                    var averageY = (p1.y + p2.y + p3.y) / 3;
                    var averageZ = (p1.z + p2.z + p3.z) / 3;
                    /*if (frontest == Vector3.zero || averageZ > frontest.z)
                    {
                        frontest = new Vector3(averageX, averageY, averageZ);
                        var plane = new Plane(p1, p2, p3);
                        frontestNormal = plane.normal;
                    }
                    if (backest == Vector3.zero || averageZ < backest.z)
                    {
                        backest = new Vector3(averageX, averageY, averageZ);
                    }*/
                    zList.Add(new PlaneInfo
                    {
                        centerPosition = new Vector3(averageX,averageY,averageZ),
                        plane = new Plane(p1, p2, p3),
                        z = averageZ,
                    });
                }
            }
            zList.Sort((a, b) => { return b.z.CompareTo(a.z); });

            float lastZ = float.MaxValue;
            Vector3 averagePos = Vector3.zero;
            int count = 0;
            for (int i = 0; i < zList.Count; i++)
            {
                if (lastZ == float.MaxValue)
                {
                    lastZ = zList[i].z;
                }
                if (zList[i].z < lastZ)
                {
                    break;
                }
                averagePos = averagePos + zList[i].centerPosition;
                count++;
            }
            frontest = averagePos / count;

            zList.Sort((a, b) => { return a.z.CompareTo(b.z); });
            averagePos = Vector3.zero;
            count = 0;
            lastZ = float.MaxValue;
            for (int i = 0; i < zList.Count; i++)
            {
                if (lastZ == float.MaxValue)
                {
                    lastZ = zList[i].z;
                }
                if (zList[i].z > lastZ)
                {
                    break;
                }
                averagePos = averagePos + zList[i].centerPosition;
                count++;
            }
            backest = averagePos / count;
            
            
            if (needOverrideGunPoint)
            {
                gunPoint.transform.forward = frontestNormal;
                //var angle = gunPoint.transform.eulerAngles;
                gunPoint.transform.SetParent(setParent ? prop.transform : null);
                if (count > 0)
                {
                    gunPoint.transform.localPosition = frontest + frontestNormal.normalized * 0.01f;
                }
                else
                {
                    gunPoint.transform.localPosition = Vector3.zero;
                }
                //gunPoint.transform.localEulerAngles = angle;

            }
            if (needOverrideBulletCase)
            {
                bulletCase.transform.forward = Vector3.right;
                //var angle = bulletCase.transform.eulerAngles;
                bulletCase.transform.SetParent(setParent ? prop.transform : null);
                if (count > 0)
                {
                    bulletCase.transform.localPosition = (frontest + backest) / 2;
                }
                else
                {
                    bulletCase.transform.localPosition = Vector3.zero;
                }
            }
            
            GameObject.DestroyImmediate(newProp);
        }

        private static string GetPathFromRoot(Transform transform,Transform root)
        {
            var str = transform.name;
            while (transform.parent)
            {
                transform = transform.parent;
                if (transform == root)
                {
                    break;
                }
                str = transform.name + "/" + str;
            }
            return str;
        }

        private static Transform CopyPoint(Transform originPointTransform,Transform originRootTransform,Transform targetTransform)
        {
            if (originPointTransform == null)
            {
                return null;
            }
            var path = GetPathFromRoot(originPointTransform, originRootTransform);
            var point = targetTransform.Find(path);
            if (point == null)
            {
                point = targetTransform.Find(originPointTransform.name);
                if (point != null)
                {
                    point.position = originPointTransform.position;
                    point.forward = originPointTransform.forward;
                    point.localScale = originPointTransform.lossyScale / targetTransform.localScale.x;
                    return point;
                }

                if (originPointTransform.parent)
                {
                    var parent = targetTransform.Find(originPointTransform.parent.name);
                    if (parent != null)
                    {
                        point = parent.Find(originPointTransform.name);
                        if (point != null)
                        {
                            point.position = originPointTransform.position;
                            point.forward = originPointTransform.forward;
                            point.localScale = originPointTransform.lossyScale / targetTransform.localScale.x;
                            return point;
                        }
                    }
                }
                if (point == null)
                {
                    point = GameObject.Instantiate(originPointTransform.gameObject).transform;
                    point.name = originPointTransform.gameObject.name;
                    //找父亲
                    if (originPointTransform.parent == null)
                    {
                        point.transform.SetParent(targetTransform);
                    }
                    else
                    {
                        var parentPath = GetPathFromRoot(originPointTransform.parent, originRootTransform);
                        var parent = targetTransform.Find(parentPath);
                        if (parent != null)
                        {
                            point.transform.SetParent(parent);
                        }
                        else
                        {
                            var parentName = originPointTransform.parent.name;
                            parent = FindChild(targetTransform, parentName);
                            if (parent != null)
                            {
                                point.transform.SetParent(parent);
                            }
                            else
                            {
                                Debug.LogError(parentName + "找不到");
                            }
                        }
                    }
                    point.localPosition = originPointTransform.localPosition;
                    point.localEulerAngles = originPointTransform.localEulerAngles;
                    point.localScale = originPointTransform.localScale;
                }
            }
            return point;
        }

        private static List<Transform> CopyPointList(List<Transform> originList,Transform originRoot,Transform targetRoot)
        {
            var targetList = new List<Transform>();
            for (int i = 0; i < originList.Count; i++)
            {
                var originPointTransform = originList[i];
                var point = CopyPoint(originPointTransform, originRoot, targetRoot);
                targetList.Add(point);
            }

            return targetList;
        }
        
        private static void CopyModelHitPoint(ModelHitPoint originModelHitPoint, ModelHitPoint modelHitPoint)
        {
            modelHitPoint.hitPoints = CopyPointList(originModelHitPoint.hitPoints, originModelHitPoint.transform,
                modelHitPoint.transform);
            
            modelHitPoint.buffEffectPoints = CopyPointList(originModelHitPoint.buffEffectPoints, originModelHitPoint.transform,
                modelHitPoint.transform);
            
            modelHitPoint.hudPoint = CopyPoint(originModelHitPoint.hudPoint, originModelHitPoint.transform, modelHitPoint.transform);
            
            modelHitPoint.buffEffectPoints = CopyPointList(originModelHitPoint.buffEffectPoints, originModelHitPoint.transform,
                modelHitPoint.transform);
            
            modelHitPoint.gunPoints = CopyPointList(originModelHitPoint.gunPoints, originModelHitPoint.transform,
                modelHitPoint.transform);
            
            modelHitPoint.bulletCastPoints = CopyPointList(originModelHitPoint.bulletCastPoints, originModelHitPoint.transform,
                modelHitPoint.transform);
            
            modelHitPoint.skillEffectPoints = CopyPointList(originModelHitPoint.skillEffectPoints, originModelHitPoint.transform,
                modelHitPoint.transform);

            modelHitPoint.hudHeight = originModelHitPoint.hudHeight;
        }

        public static void InitBuffPoint(ModelHitPoint modelHitPoint,GameObject obj,string name)
        {
            if (modelHitPoint.buffEffectPoints == null)
            {
                modelHitPoint.buffEffectPoints = new List<Transform>();
            }
            for (int j = 0; j < buffPoints.Count; j++)
            {
                Transform part = null;
                if (j == 0)
                {
                    var buff = FindChild(obj.transform, "[BuffPoint]");
                    if (buff == null)
                    {
                        buff = new GameObject("[BuffPoint]").transform;
                    }

                    var head = FindChild(obj.transform, "Bip001 Head");
                    if (head != null)
                    {
                        buff.transform.SetParent(head);
                        buff.transform.localPosition = Vector3.zero;
                        buff.transform.position += new Vector3(0,0.3f,0);
                    }
                    else
                    {
                        Debug.LogError(name + "没有找到head点");
                        buff.transform.SetParent(obj.transform);
                        buff.transform.localPosition = Vector3.zero;
                        buff.transform.position += new Vector3(0,2.2f,0);
                    }
                    part = buff;
                }
                else
                {
                    part = FindChild(obj.transform, buffPoints[j]);
                    if (part == null)
                    {
                        Debug.LogError(name + "没有找到" + buffPoints[j]);
                        part = obj.transform;
                    }
                }
                if (modelHitPoint.buffEffectPoints.Count > j)
                {
                    modelHitPoint.buffEffectPoints[j] = part;
                }
                else
                {
                    modelHitPoint.buffEffectPoints.Add(part);
                }
            }
        }
        
        private static void InitModelHitPoint(ModelHitPoint modelHitPoint,GameObject obj,string name)
        {
                            //hitpoint
                modelHitPoint.hitPoints = new List<Transform>();
                for (int j = 0; j < hitPoints.Count; j++)
                {
                    Transform part = FindChild(obj.transform, hitPoints[j]);
                    if (part == null)
                    {
                        Debug.LogError(name + "没有找到" + hitPoints[j]);
                    }
                    else
                    {
                        modelHitPoint.hitPoints.Add(part);
                    }
                }
                
                //buff
                InitBuffPoint(modelHitPoint, obj,name);
                
                //hud
                var hud = FindChild(obj.transform, "[HudPoint]");
                if (hud == null)
                {
                    hud = new GameObject("[HudPoint]").transform;
                }

                var headd = FindChild(obj.transform, "Bip001 Head");
                if (headd != null)
                {
                    hud.transform.SetParent(headd);
                    hud.transform.localPosition = Vector3.zero;
                    hud.transform.position += new Vector3(0,0,0);
                }
                else
                {
                    Debug.LogError(name + "没有找到head点");
                    hud.transform.SetParent(obj.transform);
                    hud.transform.localPosition = Vector3.zero;
                    hud.transform.position += new Vector3(0,2.2f,0);
                }

                modelHitPoint.hudPoint = hud;
                modelHitPoint.hudHeight = 0.6f;
                GameObject gunPoint = null;
                GameObject bulletCase = null;
                var prop = FindChild(obj.transform, "Bip001 Prop1");
                if (prop != null)
                {
                    CreateWeaponPoints(prop.gameObject,ref gunPoint,ref bulletCase,true);
                    if (gunPoint)
                    {
                        modelHitPoint.gunPoints = new List<Transform> {gunPoint.transform};
                    }

                    if (bulletCase)
                    {
                        modelHitPoint.bulletCastPoints = new List<Transform> {bulletCase.transform};
                    }
                }
        }
        
        private static Dictionary<string, string> animationNameDic = new Dictionary<string, string>
        {
            ["KnockBack"] = "HitFly",
            ["KnockStand"] = "StandUp",
            ["Stand_Hit"] = "Hit",
        };

        [MenuItem("GTATools/GamePlay/RpgModel/重新赋值受击动作", false, 66778899)]
        public static void RefreshAnimation()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var animator = gameObjects[i].GetComponent<Animator>();
                ApplyAnimationToAnimator(gameObjects[i], animator);
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        private static void ApplyAnimationToAnimator(GameObject originPrefab,Animator animator)
        {
            var avatar = animator.avatar;
            var avatarPath = AssetDatabase.GetAssetPath(avatar);
            var modelDirectory = Directory.GetParent(avatarPath);
            if (modelDirectory != null)
            {
                var rootDirectory = modelDirectory.Parent;
                if (rootDirectory != null)
                {
                    var animatorController = animator.runtimeAnimatorController as AnimatorOverrideController;
                    var overrides =
                        new List<KeyValuePair<AnimationClip, AnimationClip>>(animatorController.overridesCount);
                    animatorController.GetOverrides(overrides);
                    var animationsPath = rootDirectory.FullName + "\\Animations";
                    if (!Directory.Exists(animationsPath))
                    {
                        Debug.LogError("没有找到动画文件");
                        return;
                    }

                    var animationsFiles = Directory.GetFiles(animationsPath);
                    for (int k = 0; k < overrides.Count; k++)
                    {
                        var originName = overrides[k].Key.name;
                        if (animationNameDic.TryGetValue(originName, out var lastName))
                        {
                            var hasFound = false;
                            for (int o = 0; o < animationsFiles.Length; o++)
                            {
                                if (animationsFiles[o].ToLower().EndsWith(".fbx"))
                                {
                                    var animationPath = GetAssetPathByDirectoryPath(animationsFiles[o]);
                                    var clips = AssetDatabase.LoadAllAssetsAtPath(animationPath);
                                    for (int oo = 0; oo < clips.Length; oo++)
                                    {
                                        if (clips[oo] is AnimationClip clip && clip.name.EndsWith(lastName))
                                        {
                                            overrides[k] =
                                                new KeyValuePair<AnimationClip, AnimationClip>(overrides[k].Key,
                                                    clip);
                                            hasFound = true;
                                            break;
                                        }
                                    }
                                }
                            }
                            if (!hasFound)
                            {
                                Debug.LogError(originPrefab.name + " " + originName + "没有对应的动作");
                            }
                        }
                    }
                    animatorController.ApplyOverrides(overrides);
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }
            }
        }
        

        [MenuItem("GTATools/GamePlay/RpgModel/刷新buff点位", false, 66778899)]
        public static void RefreshBuffPoint()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var obj = GameObject.Instantiate(gameObjects[i]);
                var modelHitPoint = obj.GetOrAddComponent<ModelHitPoint>();
                if (modelHitPoint != null)
                {
                    InitBuffPoint(modelHitPoint,obj,obj.name);
                    PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                    GameObject.DestroyImmediate(obj);
                }
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        
        [MenuItem("GTATools/GamePlay/RpgModel/根据美术prefab创建程序prefab", false, 66778899)]
        public static void CreatePrefabFroArt()
        {
            var gameObjects = Selection.gameObjects;
            for (int i = 0; i < gameObjects.Length; i++)
            {
                var name = gameObjects[i].name;
                var obj = GameObject.Instantiate(gameObjects[i]);
                var modelHitPoint = obj.GetOrAddComponent<ModelHitPoint>();
                obj.transform.localPosition = Vector3.zero;
                obj.transform.localEulerAngles = Vector3.zero;
                //先找到程序目录下的prefab，获取他的modelhitpoint
                var originPrefabPath = "Assets/ResourcesAssets/Pve/Prefabs/Hero/" + name + ".prefab";
                var originPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(originPrefabPath);
                ModelHitPoint originModelHitPoint = null;
                if (originPrefab)
                {
                    originModelHitPoint = originPrefab.GetComponent<ModelHitPoint>();
                }

                if (originModelHitPoint != null)
                {
                    CopyModelHitPoint(originModelHitPoint, modelHitPoint);
                }
                else
                {
                    InitModelHitPoint(modelHitPoint, obj, name);
                }

                var animator = obj.GetComponentInChildren<Animator>();
                if (animator)
                {
                    
                    var avatar = animator.avatar;
                    var avatarPath = AssetDatabase.GetAssetPath(avatar);
                    var modelDirectory = Directory.GetParent(avatarPath);
                    if (modelDirectory != null)
                    {
                        var rootDirectory = modelDirectory.Parent;
                        if (rootDirectory != null)
                        {
                            bool hasAnimator = false;
                            if (originPrefab != null)
                            {
                                var originAnimator = originPrefab.GetComponent<Animator>();
                                if (originAnimator && originAnimator.runtimeAnimatorController)
                                {
                                    animator.runtimeAnimatorController = originAnimator.runtimeAnimatorController;
                                    hasAnimator = true;
                                }
                            }
                            /*var dirs = rootDirectory.GetDirectories();
                            for (int j = 0; j < dirs.Length; j++)
                            {
                                if (dirs[j].Name.ToLower().Contains("animator"))
                                {
                                    var files = dirs[j].GetFiles();
                                    for (int k = 0; k < files.Length; k++)
                                    {
                                        var file = files[k];
                                        if (file.Name.ToLower().EndsWith(".controller"))
                                        {
                                            var assetPath = GetAssetPathByDirectoryPath(files[k].FullName);
                                            animator.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(assetPath);
                                            hasAnimator = true;
                                        }
                                    }
                                    break;
                                }
                            }*/
                            if (!hasAnimator)
                            {
                                Debug.LogError(name + "没有找到状态机");
                                //帮他创建一个状态机
                                var templateAnimatorPath =
                                    "Assets/Arts/Character/Role/hero/Template/Rpg/Animator/HeroTemplateAFK.controller";
                                var templateAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorController>(templateAnimatorPath);
                                var animatorControllerPath = rootDirectory.FullName + "\\Animator";
                                if (!Directory.Exists(animatorControllerPath))
                                {
                                    Directory.CreateDirectory(animatorControllerPath);
                                }
                                var animatorController = new AnimatorOverrideController();
                                animatorController.runtimeAnimatorController = templateAnimatorController;
                                
                                //替换动作

                                var overrides =
                                    new List<KeyValuePair<AnimationClip, AnimationClip>>(animatorController.overridesCount);
                                animatorController.GetOverrides(overrides);
                                var animationsPath = rootDirectory.FullName + "\\Animations";
                                if (!Directory.Exists(animationsPath))
                                {
                                    Debug.LogError("没有找到动画文件");
                                    continue;
                                }
                                var animationsFiles = Directory.GetFiles(animationsPath);
                                
                                for (int k = 0; k < overrides.Count; k++)
                                {
                                    //overrides[k] = 
                                    var originName = overrides[k].Key.name;
                                    bool hasFound = false;
                                    //遍历动作
                                    for (int o = 0; o < animationsFiles.Length; o++)
                                    {
                                        if (hasFound)
                                        {
                                            break;
                                        }
                                        if (animationsFiles[o].ToLower().EndsWith(".fbx"))
                                        {
                                            var animationPath = GetAssetPathByDirectoryPath(animationsFiles[o]);
                                            var clips = AssetDatabase.LoadAllAssetsAtPath(animationPath);
                                            for (int oo = 0; oo < clips.Length; oo++)
                                            {
                                                if (clips[oo] is AnimationClip clip && CheckIsNameMatch(clip.name,originName))
                                                {
                                                    overrides[k] = new KeyValuePair<AnimationClip, AnimationClip>(overrides[k].Key,clip);
                                                    hasFound = true;
                                                }
                                            }
                                        }
                                    }

                                    if (!hasFound)
                                    {
                                        Debug.LogError(originName+"没有对应的动作");
                                    }
                                }
                                animatorController.ApplyOverrides(overrides);

                                var assetPath = GetAssetPathByDirectoryPath(animatorControllerPath) + "/" + name +
                                                ".overrideController";
                              
                                AssetDatabase.CreateAsset(animatorController,assetPath);
                                AssetDatabase.SaveAssets();
                                AssetDatabase.Refresh();
                                animator.runtimeAnimatorController = AssetDatabase.LoadAssetAtPath<AnimatorOverrideController>(assetPath);
                            }
                        }
                    }
                }

                if (originPrefab)
                {
                    var aimIk = originPrefab.GetComponent<AimIK>();
                    if (aimIk)
                    {
                        var newAimIk = ComponentUtil.CopyComponent<AimIK>(aimIk,originPrefab);
                        newAimIk.solver.transform = aimIk.solver.transform;
                        newAimIk.solver.bones = new IKSolver.Bone[aimIk.solver.bones.Length];
                        for (int j = 0; j < aimIk.solver.bones.Length; j++)
                        {
                            newAimIk.solver.bones[j] = new IKSolver.Bone(FindChild(obj.transform, aimIk.solver.bones[j].transform.name));
                        }
                    }
                }
                //
                
                var lightElement = obj.GetOrAddComponent<LightElement>();
                lightElement.controllerMark = "rpgScene";
                
                PrefabUtility.SaveAsPrefabAsset(obj, AssetDatabase.GetAssetPath(gameObjects[i]));
                GameObject.DestroyImmediate(obj);
                
                lightElement = gameObjects[i].GetOrAddComponent<LightElement>();
                lightElement.FindLightRenderer();
            }
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
        
        //动作别名映射
        private static Dictionary<string, string> animationAliasName = new Dictionary<string, string>()
        {
            ["KnockBack"] = "HitFly",
            ["KnockStand"] = "StandUp",
            ["Stand_Shoot_Process"] = "Attack",
        };

        private static bool CheckIsNameMatch(string clipName,string originName)
        {
            if (clipName.EndsWith(originName))
            {
                return true;
            }
            if (animationAliasName.TryGetValue(originName, out var aliasName))
            {
                return clipName.EndsWith(aliasName);
            }
            return false;
        }
        
        // [MenuItem("GameObject/Rpg/SkillTimeline", false, 12)]
        // public static void SkillTimeline()
        // {
        //     var layerName = "PveMap";
        //     var layer = LayerMask.NameToLayer(layerName);
        //     var gameObjects = Selection.gameObjects;
        //     for (int i = 0; i < gameObjects.Length; i++)
        //     {
        //         var obj = gameObjects[i];
        //         obj.SetLayerRecursively(layer);
        //         var skillTimeline = gameObjects[i].GetOrAddComponent<RpgSkillTimeline>();
        //         skillTimeline.director = obj.GetComponentInChildren<PlayableDirector>();
        //         if (skillTimeline.director == null)
        //         {
        //             Debug.LogError(obj.name + " 没有PlayableDirector");
        //         }
        //
        //         var camera = gameObjects[i].GetComponentInChildren<Camera>();
        //         if (camera == null)
        //         {
        //             Debug.LogError(obj.name + " 没有相机");
        //         }
        //         else
        //         {
        //             camera.cullingMask = 1 << layer;
        //         }
        //         skillTimeline.camera = camera.gameObject;
        //     }
        // }
        
        [MenuItem("GTATools/GamePlay/RTS/GenerateColorOffset", false, 0)]
        public static void GenerateColorOffset()
        {
            var objects = Selection.objects;
            if (objects.Length == 0)
            {
                return;
            }

            var path = AssetDatabase.GetAssetPath(objects[0] as Texture2D);
            object[] allSubAssets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(path).Where(o=>objects[0]!=o).ToArray();

            ///获取精灵的数量
            int startIndex = 0;
            if (allSubAssets[0] is Texture2D)
            {
                startIndex = 1;
            }

            SpriteAnimationX sax = null;
            Sprite firstSprite = null;
            Sprite tmpSprite;
            int _fi = 0;
            // 创建动画对象
            sax = new SpriteAnimationX(path);
           
            for (int i = startIndex; i < allSubAssets.Length; i++)
            {
                tmpSprite = allSubAssets[i] as Sprite;
                if (tmpSprite)
                {
                    if (sax.texture == null)
                    {
                        sax.texture = tmpSprite.texture;
                    }
                    _fi++;
                    // 序列帧命名协议： 动作-方向-帧数
                    string[] names = tmpSprite.name.Split('-');
                    string actionName;
                    int frame = 0;
                    int dir = 0;
                    int changeSpriteType = 0;
                    if (names.Length == 4)
                    {
                        actionName = names[1];
                        int.TryParse(names[2], out dir);
                        dir = dir - 1;
                        int.TryParse(names[3].Split('(')[0], out frame);
                        if (frame != 0) //防止帧数是从0开始命名的
                        {
                            frame = frame - 1;
                        }

                        if (names[0] == "mask")
                        {
                            changeSpriteType = 1;
                        }
                        else if (names[0] == "mask1")
                        {
                            changeSpriteType = 2;
                        }
                    }
                    else
                    {
                        Debug.LogError("error");
                        return;
                    }   

                    //方向
                    SpriteAnimationAction spriteAnimAction;
                    if (!sax.actions.TryGetValue(actionName, out spriteAnimAction))
                    {
                        spriteAnimAction = new SpriteAnimationAction(actionName);
                        sax.actions.Add(actionName, spriteAnimAction);
                    }

                    //帧
                    Dictionary<int, SpriteData> spriteList;
                    if (!spriteAnimAction.directionSpList.TryGetValue(dir, out spriteList))
                    {
                        spriteList = new Dictionary<int, SpriteData>();
                        spriteAnimAction.directionSpList.Add(dir, spriteList);
                    }

                    var sprite = UnityEngine.Object.Instantiate((Sprite) allSubAssets[i]);
                    if (!spriteList.ContainsKey(frame))
                    {
                        spriteList.Add(frame, new SpriteData());
                    }
                    if (changeSpriteType == 1)
                    {
                        spriteList[frame].changeColorSprite1 = sprite;
                    }
                    else if (changeSpriteType == 2)
                    {
                        spriteList[frame].changeColorSprite2 = sprite;
                    }
                    else
                    {
                        spriteList[frame].sprite = sprite;
                        //由于显示的大小会根据第一个精灵的大小来进行缩放，所以要找到第一个精灵
                        if (firstSprite == null)
                        {
                            firstSprite = tmpSprite;
                        }
                        else if (string.Compare(firstSprite.name, tmpSprite.name, StringComparison.Ordinal) > 0)
                        {
                            firstSprite = tmpSprite;
                        }
                    }
                    
                    
                }
            }
            foreach (var action in sax.actions)
            {
                foreach (var item in action.Value.directionSpList)
                {
                    foreach (var it in item.Value)
                    {
                        var item2 = it.Value;
                        if (item2.changeColorSprite1)
                        {
                            //找到sprite最左上角的alpha为奇数的点
                            var texture = item2.sprite.texture;
                            var pixels = texture.GetPixels32();
                            var rect = item2.sprite.rect;
                            var x = 0;
                            var y = 0;
                            bool hasFound = false;
                            var xOffset = item2.sprite.pivot.x + rect.x;
                            var yOffset = item2.sprite.pivot.y + rect.y;
                            for (int i = (int)rect.x; i < rect.x + rect.width; i++)
                            {
                                for (int j = (int) rect.y; j < rect.y + rect.height; j++)
                                {
                                    var idx = (texture.height - j) * texture.width + i;
                                    var a = (int) (pixels[idx].a);
                                    if (a % 2 == 1)
                                    {
                                        x = i - (int)rect.x;
                                        y = j - (int)rect.y;
                                        hasFound = true;
                                        break;
                                    }
                                }
                                if (hasFound)
                                {
                                    break;
                                }
                            }

                            rect = item2.changeColorSprite1.rect;
                            var xOffset2 = item2.changeColorSprite1.pivot.x + rect.x;
                            var yOffset2 = item2.changeColorSprite1.pivot.y + rect.y;
                            var offset = item2.changeColorSprite1.rect.position - item2.sprite.rect.position;
                            item2.offset1 = new Vector2(xOffset2 - xOffset,yOffset2 - yOffset);//new Vector2(offset.x / sax.texture.width,offset.y / sax.texture.height);
                            rect = item2.changeColorSprite1.rect;
                            hasFound = false;
                            for (int i = (int)rect.x; i < rect.x + rect.width; i++)
                            {
                                for (int j = (int) rect.y; j < rect.y + rect.height; j++)
                                {
                                    var idx = (texture.height - j) * texture.width + i;
                                    var a = (int) (pixels[idx].a);
                                    if (a > 0)
                                    {
                                        item2.startOffset = new Vector2(x - (i - (int)rect.x), y - (j - (int)rect.y));
                                        //Debug.LogError(item2.startOffset);
                                        hasFound = true;
                                        break;
                                    }
                                }

                                if (hasFound)
                                {
                                    break;
                                }
                            }
                            Debug.LogError(action.Key + "_" + item.Key + "_" + it.Key + " " +item2.offset1);
                        }
                        if (item2.changeColorSprite2)
                        {
                            var offset = item2.changeColorSprite2.rect.position - item2.sprite.rect.position;
                            item2.offset2 = new Vector2(offset.x / sax.texture.width,offset.y / sax.texture.height);
                        }
                    }
                }
            }
        }

    }
    
   

    [CustomEditor(typeof(ModelHitPoint))]
    public class ModelHitPointInspector : UnityEditor.Editor
    {
        private int state = 0;
        private Vector3 startPosition;
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            var modelHitPoint = target as ModelHitPoint;
            if (modelHitPoint.bulletPoints != null && modelHitPoint.templateBulletPoint != null)
            {
                EditorGUILayout.BeginVertical();
                if (modelHitPoint.bulletPointsType == null)
                {
                    modelHitPoint.bulletPointsType = new List<int>();
                }

                /*if (modelHitPoint.bulletPointsType.Count < modelHitPoint.bulletPoints.Count)
                {
                    var diff = modelHitPoint.bulletPoints.Count - modelHitPoint.bulletPointsType.Count;
                    for (int i = 0; i < diff; i++)
                    {
                        modelHitPoint.bulletPointsType.Add(0);
                    }
                }*/
                
                for (int i = 0; i < modelHitPoint.bulletPoints.Count; i++)
                {
                    if (modelHitPoint.bulletPoints[i] == null)
                    {
                        var newObject = new GameObject("[BulletPoint"+i+"]");
                        var bulletParent = modelHitPoint.transform.Find("[BulletPointsRoot]");
                        if (bulletParent == null)
                        {
                            bulletParent = (new GameObject("[BulletPointsRoot]").transform);
                            bulletParent.SetParent(modelHitPoint.transform);
                        }
                        newObject.transform.SetParent(bulletParent);
                        modelHitPoint.bulletPoints[i] = newObject.transform;
                    }

                    EditorGUILayout.BeginHorizontal();
                    if (GUILayout.Button("赋值点位"+i))
                    {
                        modelHitPoint.bulletPoints[i].transform.position = modelHitPoint.templateBulletPoint.position;
                        modelHitPoint.bulletPoints[i].transform.forward = modelHitPoint.templateBulletPoint.forward;
                    }

                    /*var type = modelHitPoint.bulletPointsType[i].ToString();
                    type = GUILayout.TextField(type);
                    if (int.TryParse(type, out var t))
                    {
                        modelHitPoint.bulletPointsType[i] = t;
                    }*/
                    EditorGUILayout.EndHorizontal();
                }

                if (modelHitPoint.bulletPointsSpeedType == null)
                {
                    modelHitPoint.bulletPointsSpeedType = new List<int>();
                }
                if (state == 0)
                {
                    for (int i = 0; i < modelHitPoint.bulletPointSpeed.Count; i++)
                    {
                        if (GUILayout.Button("开始记录偏移"+i))
                        {
                            startPosition = modelHitPoint.templateBulletPoint.position;
                            state = 1;
                        }
                    }
                }
                else if (state == 1)
                {
                    for (int i = 0; i < modelHitPoint.bulletPointSpeed.Count; i++)
                    {
                        if (GUILayout.Button("结束记录偏移"+i))
                        {
                            var offset = (modelHitPoint.templateBulletPoint.position - startPosition).normalized;
                            modelHitPoint.bulletPointSpeed[i] = offset;
                            state = 0;
                        }
                    }
                }
                
                EditorGUILayout.EndVertical();
            }
        }
    }
}